import assert from 'assert/strict'
import test from 'node:test'

import { camelToSnakeCase, diffItems, extractProperty, generateToken, parseSize, parseXml } from './utils.mjs'

const { describe, it } = test

// ===================================================================

describe('camelToSnakeCase()', function () {
  it('converts a string from camelCase to snake_case', function () {
    assert.equal(camelToSnakeCase('fooBar'), 'foo_bar')
    assert.equal(camelToSnakeCase('ipv4Allowed'), 'ipv4_allowed')
  })

  it('does not alter snake_case strings', function () {
    assert.equal(camelToSnakeCase('foo_bar'), 'foo_bar')
    assert.equal(camelToSnakeCase('ipv4_allowed'), 'ipv4_allowed')
  })

  it('does not alter upper case letters expect those from the camelCase', function () {
    assert.equal(camelToSnakeCase('fooBar_BAZ'), 'foo_bar_BAZ')
  })
})

// -------------------------------------------------------------------

describe('diffItems', () => {
  it('computes the added/removed items between 2 iterables', () => {
    assert.deepEqual(diffItems(['foo', 'bar'], ['baz', 'foo']), [['bar'], ['baz']])
  })
})

// -------------------------------------------------------------------

describe('extractProperty()', function () {
  it('returns the value of the property', function () {
    const value = {}
    const obj = { prop: value }

    assert.equal(extractProperty(obj, 'prop'), value)
  })

  it('removes the property from the object', function () {
    const value = {}
    const obj = { prop: value }

    assert.equal(extractProperty(obj, 'prop'), value)
    assert.equal(obj.prop, undefined)
  })
})

// -------------------------------------------------------------------

describe('parseXml()', () => {
  // excerpt of http://updates.xensource.com/XenServer/updates.xml
  const strA = `<?xml version="1.0" ?>
<patchdata>
  <!-- Generated by cfu.py, do not edit -->
  <patches>
    <patch after-apply-guidance="" name-description="Security update when starting Linux VMs." name-label="Hotfix 2007-001" patch-url="http://downloadns.citrix.com.edgesuite.net/akdlm/9618/2007-001.zip" releasenotes="" timestamp="2007-09-19T00:00:00Z" url="https://support.citrix.com/article/CTX118090" uuid="0701" version="1.0">
      <!-- serverversion = '4.0.1' -->
    </patch>
    <patch after-apply-guidance="" name-description="Stability update for large hotfixes." name-label="Hotfix 2007-002" patch-url="http://downloadns.citrix.com.edgesuite.net/akdlm/9618/2007-002.zip" releasenotes="" timestamp="2007-10-29T00:00:00Z" url="https://support.citrix.com/article/CTX118097" uuid="0702" version="1.0">
      <!-- serverversion = '4.0.1' -->
    </patch>
  </patches>
</patchdata>`

  const bufA = Buffer.from(strA)
  const resultA = {
    patchdata: {
      patches: {
        patch: [
          {
            'after-apply-guidance': '',
            'name-description': 'Security update when starting Linux VMs.',
            'name-label': 'Hotfix 2007-001',
            'patch-url': 'http://downloadns.citrix.com.edgesuite.net/akdlm/9618/2007-001.zip',
            releasenotes: '',
            timestamp: '2007-09-19T00:00:00Z',
            url: 'https://support.citrix.com/article/CTX118090',
            uuid: '0701',
            version: '1.0',
          },
          {
            'after-apply-guidance': '',
            'name-description': 'Stability update for large hotfixes.',
            'name-label': 'Hotfix 2007-002',
            'patch-url': 'http://downloadns.citrix.com.edgesuite.net/akdlm/9618/2007-002.zip',
            releasenotes: '',
            timestamp: '2007-10-29T00:00:00Z',
            url: 'https://support.citrix.com/article/CTX118097',
            uuid: '0702',
            version: '1.0',
          },
        ],
      },
    },
  }
  const strB = `<?xml version="1.0" ?>
<iscsi-target>
  <LUN>
    <vendor>TrueNAS</vendor>
    <serial>9eaa394581f3003</serial>
    <LUNid>55</LUNid>
    <size>10995116277760</size>
    <SCSIid>36589cfc000000581d40d6d5140d9b9da</SCSIid>
  </LUN>
  <LUN>
    <vendor>TrueNAS</vendor>
    <serial>9eaa394581f3004</serial>
    <LUNid>56</LUNid>
    <size>10995116277761</size>
    <SCSIid>36589cfc000000581d40d6d5140d9b9df</SCSIid>
  </LUN>
</iscsi-target>`

  const bufB = Buffer.from(strB)
  const resultB = {
    'iscsi-target': {
      LUN: [
        {
          vendor: 'TrueNAS',
          serial: '9eaa394581f3003',
          LUNid: '55',
          size: '10995116277760',
          SCSIid: '36589cfc000000581d40d6d5140d9b9da',
        },
        {
          vendor: 'TrueNAS',
          serial: '9eaa394581f3004',
          LUNid: '56',
          size: '10995116277761',
          SCSIid: '36589cfc000000581d40d6d5140d9b9df',
        },
      ],
    },
  }

  it('supports strings', () => {
    assert.deepEqual(parseXml(strA), resultA)
    assert.deepEqual(parseXml(strB), resultB)
  })

  it('supports buffers', () => {
    assert.deepEqual(parseXml(bufA), resultA)
    assert.deepEqual(parseXml(bufB), resultB)
  })
})

// -------------------------------------------------------------------

describe('generateToken()', () => {
  it('generates a string', async () => {
    assert.equal(typeof (await generateToken()), 'string')
  })
})

// -------------------------------------------------------------------

describe('parseSize()', function () {
  it('parses a human size', function () {
    assert.equal(parseSize('1G'), 1e9)
  })

  it('returns the parameter if already a number', function () {
    assert.equal(parseSize(1e6), 1e6)
  })

  it('throws if the string cannot be parsed', function () {
    assert.throws(function () {
      parseSize('foo')
    })
  })

  it('supports the B unit as suffix', function () {
    assert.equal(parseSize('3MB'), 3e6)
  })
})
